package com.soft.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Component;

import com.soft.dao.BaseDao;
import com.soft.support.Pager;

@SuppressWarnings({"rawtypes", "unchecked"})
@Component("baseDao")
public class BaseDaoImpl implements BaseDao {
	private HibernateTemplate hibernateTemplate;

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		hibernateTemplate = new HibernateTemplate(sessionFactory);
	}

	public void save(final Object o) {
		this.hibernateTemplate.save(o);
	}
	
	public void update(final Object o) {
		this.hibernateTemplate.update(o);
	}

	public void saveOrUpdate(final Object o) {
		this.hibernateTemplate.saveOrUpdate(o);
	}

	public void delete(final Object o) {
		this.hibernateTemplate.delete(o);
	}
	
	public void delete(final Class c, final Serializable id) {
		this.hibernateTemplate.delete(this.get(c, id));
	}
	
	public Object get(final Class c, final Serializable id) {
		return this.hibernateTemplate.get(c, id);
	}
	
	public Object findUniqueByProperty(final Class c, final String propertyName, final Object value) {
        Object t = this.hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(c).add(Restrictions.eq(propertyName, value));
                Object t = criteria.uniqueResult();
                return t;
            }
        });
        return t;
    }
	
	public List findAll(final Class c, final Order[] orders, final Criterion ...criterions){
        return findByCriteria(c, orders, 0, 0, criterions);
    }
	
	public List findByCriteria(final Class c, final Order[] orders, final int firstResult, final int maxResults, final Criterion ...criterions){
        List list = (List)this.hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(c);
                for(Criterion criterion : criterions){
                    criteria.add(criterion);
                }
                if (orders != null) {
                	for (Order order : orders) {
                		criteria.addOrder(order);
                	}
                }
                if(maxResults != 0){
                    criteria.setFirstResult(firstResult);
                    criteria.setMaxResults(maxResults);
                }
                List list = criteria.list();
                return list;
            }
        });
        return list;
    }
	
	public List findByCriteria(final Class c, final Order[] orders, final int firstResult, final int maxResults, final List<Criterion> criterions){
        List list = (List)this.hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(c);
                for(Criterion criterion : criterions){
                    criteria.add(criterion);
                }
                if (orders != null) {
                	for (Order order : orders) {
                		criteria.addOrder(order);
                	}
                }
                if(maxResults != 0){
                    criteria.setFirstResult(firstResult);
                    criteria.setMaxResults(maxResults);
                }
                List list = criteria.list();
                return list;
            }
        });
        return list;
    }
	
	public int findCountsByCriteria(final Class c, final Criterion ...criterions){
        int totalCounts = (Integer)this.hibernateTemplate.execute(new HibernateCallback(){
        public Object doInHibernate(Session session)
                throws HibernateException, SQLException {
            Criteria criteria = session.createCriteria(c);
            for(Criterion criterion : criterions){
                criteria.add(criterion);
            }
            int totalCounts = criteria.list().size();
            return totalCounts;
	        }
	    });
        return totalCounts;
	}
	
	public int findCountsByCriteria(final Class c, final List<Criterion> criterions){
        int totalCounts = (Integer)this.hibernateTemplate.execute(new HibernateCallback(){
        public Object doInHibernate(Session session)
                throws HibernateException, SQLException {
            Criteria criteria = session.createCriteria(c);
            for(Criterion criterion : criterions){
                criteria.add(criterion);
            }
            int totalCounts = criteria.list().size();
            return totalCounts;
	        }
	    });
        return totalCounts;
	}
	
	public Pager findForPager(final Class c, final Order[] orders, final int firstResult, final int maxResults, final Criterion ...criterions){
        int total = findCountsByCriteria(c, criterions);
        List list = findByCriteria(c, orders, firstResult, maxResults, criterions);
        Pager pager = new Pager();
        pager.setTotal(total);
        pager.setDatas(list);
        return pager;
    }
	
	public Pager findForPager(final Class c, final Order[] orders, final int firstResult, final int maxResults, final List<Criterion> criterions){
        int total = findCountsByCriteria(c, criterions);
        List list = findByCriteria(c, orders, firstResult, maxResults, criterions);
        Pager pager = new Pager();
        pager.setTotal(total);
        pager.setDatas(list);
        return pager;
    }
	
	public List findByProperty(final Class c, final Order[] orders, final String propertyName, final Object value){
        Criterion criterion = Restrictions.eq(propertyName, value);
        List list = findAll(c, orders, criterion);
        return list;
    }
	
	public boolean isPropertyExist(final Class c, final String propertyName, final Object value){
        boolean isExist = (Boolean)this.hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(c).add(Restrictions.eq(propertyName, value));
                boolean isEmpty = criteria.list().isEmpty();
                return ! isEmpty;
            }
        });
        return isExist;
    }

	public Object execSQL(String sql) {
		// TODO Auto-generated method stub
		return null;
	}

}
